package com.example.palette.util;

import android.content.ContentResolver;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.ColorMatrix;
import android.graphics.ColorMatrixColorFilter;
import android.graphics.Matrix;
import android.graphics.Paint;
import android.graphics.Rect;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.graphics.drawable.VectorDrawable;
import android.net.Uri;
import android.os.Build;
import android.util.Base64;
import android.widget.ImageView;

import androidx.appcompat.content.res.AppCompatResources;
import androidx.core.content.ContextCompat;

import com.google.zxing.BarcodeFormat;
import com.google.zxing.EncodeHintType;
import com.google.zxing.common.BitMatrix;
import com.google.zxing.qrcode.QRCodeWriter;
import com.google.zxing.qrcode.decoder.ErrorCorrectionLevel;

import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.HashMap;
import java.util.Map;

public class BitmapUtil {
    public static final int DEFAULT_MAX_WIDTH = 1920;
    public static final int DEFAULT_MAX_HEIGHT = 1080;

    /**
     * 回收bitmap
     *
     * @param bitmap
     */
    public static void recycle(Bitmap bitmap) {
        if (bitmap != null && !bitmap.isRecycled()) {
            bitmap.recycle();
            bitmap = null;
        }
    }

    /**
     * 回收imageView的bitmap
     *
     * @param imageView
     */
    public static void recycle(ImageView imageView) {
        if (imageView != null) {
            try {
                Drawable drawable = imageView.getDrawable();
                if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP && drawable instanceof VectorDrawable) {
                    VectorDrawable vectorDrawable = (VectorDrawable) imageView.getDrawable();
                    vectorDrawable.clearColorFilter();
                } else {
                    BitmapDrawable srcBitmap = (BitmapDrawable) imageView.getDrawable();
                    if (srcBitmap != null) {
                        Bitmap bitmap = srcBitmap.getBitmap();
                        recycle(bitmap);
                    }
                    BitmapDrawable backBitmap = (BitmapDrawable) imageView.getBackground();
                    if (backBitmap != null) {
                        Bitmap bitmap = backBitmap.getBitmap();
                        recycle(bitmap);
                    }
                }
            } catch (Throwable e) {
                e.printStackTrace();
            }
            imageView.setImageBitmap(null);
        }
    }

    /**
     * 设置bitmap色彩饱和度
     *
     * @param bitmap
     * @param sat
     * @return
     */
    public Bitmap saturationForBitmap(Bitmap bitmap, float sat) {
        Bitmap temp = Bitmap.createBitmap(bitmap.getWidth(), bitmap.getHeight(), Bitmap.Config.ARGB_8888);
        Canvas canvas = new Canvas(temp);
        Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG);
        ColorMatrix saturationColorMatrix = new ColorMatrix();
        saturationColorMatrix.setSaturation(sat);
        ColorMatrix ImageMatrix = new ColorMatrix();
        ImageMatrix.postConcat(saturationColorMatrix);
        paint.setColorFilter(new ColorMatrixColorFilter(ImageMatrix));
        canvas.drawBitmap(bitmap, 0, 0, paint);
        return temp;
    }

    /**
     * 缩放bitmap
     *
     * @param bitmap
     * @param destWidth
     * @param destHeight
     * @return
     */
    public static Bitmap scaleBitmap(Bitmap bitmap, int destWidth, int destHeight) {
        if (destWidth < 0) {
            destWidth = DEFAULT_MAX_WIDTH;
        }
        if (destHeight < 0) {
            destHeight = DEFAULT_MAX_HEIGHT;
        }
        return Bitmap.createScaledBitmap(bitmap, destWidth, destHeight, true);
    }

    /**
     * uri转bitmap
     *
     * @param context
     * @param uri
     * @param destWidth
     * @param destHeight
     * @return
     */
    public static Bitmap uriToBitmap(Context context, Uri uri, int destWidth, int destHeight) {
        ContentResolver contentResolver = context.getContentResolver();
        byte[] data;
        try {
            InputStream input;
            input = contentResolver.openInputStream(uri);
            data = new byte[input.available()];
            input.read(data);
            input.close();
        } catch (IOException e) {
            e.printStackTrace();
            return null;
        }
        return bytesToBitmap(data, destWidth, destHeight);
    }

    /**
     * png、jpg转bitmap
     *
     * @param context
     * @param resId
     * @param destWidth
     * @param destHeight
     * @return
     */
    public static Bitmap pngToBitmap(Context context, int resId, int destWidth, int destHeight) {
        if (destWidth < 0) {
            destWidth = DEFAULT_MAX_WIDTH;
        }
        if (destHeight < 0) {
            destHeight = DEFAULT_MAX_HEIGHT;
        }
        BitmapFactory.Options options = new BitmapFactory.Options();
        options.inJustDecodeBounds = true;
        BitmapFactory.decodeResource(context.getResources(), resId, options);
        options.inSampleSize = calculateInSampleSize(destWidth, destHeight, options);
        options.inJustDecodeBounds = false;
        return BitmapFactory.decodeResource(context.getResources(), resId, options);
    }

    /**
     * vector转bitmap
     *
     * @param context
     * @param vectorResId
     * @return
     */
    public static Bitmap vectorToBitmap(Context context, int vectorResId) {
        Drawable drawable;
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
            drawable = ContextCompat.getDrawable(context, vectorResId);
        } else {
            drawable = AppCompatResources.getDrawable(context, vectorResId);
        }
        Bitmap result = Bitmap.createBitmap(drawable.getIntrinsicWidth(), drawable.getIntrinsicHeight(), Bitmap.Config.ARGB_8888);
        Canvas canvas = new Canvas(result);
        drawable.setBounds(0, 0, canvas.getWidth(), canvas.getHeight());
        drawable.draw(canvas);
        return result;
    }

    /**
     * 文件转bitmap
     *
     * @param filePath
     * @param destWidth
     * @param destHeight
     * @return
     */
    public static Bitmap fileToBitmap(String filePath, int destWidth, int destHeight) {
        if (destWidth < 0) {
            destWidth = DEFAULT_MAX_WIDTH;
        }
        if (destHeight < 0) {
            destHeight = DEFAULT_MAX_HEIGHT;
        }
        BitmapFactory.Options options = new BitmapFactory.Options();
        options.inJustDecodeBounds = true;
        BitmapFactory.decodeFile(filePath, options);
        options.inSampleSize = calculateInSampleSize(destWidth, destHeight, options);
        options.inJustDecodeBounds = false;
        return BitmapFactory.decodeFile(filePath, options);
    }

    /**
     * 流转bitmap
     *
     * @param is
     * @param destWidth
     * @param destHeight
     * @return
     */
    public static Bitmap streamToBitmap(InputStream is, int destWidth, int destHeight) {
        if (destWidth < 0) {
            destWidth = DEFAULT_MAX_WIDTH;
        }
        if (destHeight < 0) {
            destHeight = DEFAULT_MAX_HEIGHT;
        }
        BitmapFactory.Options options = new BitmapFactory.Options();
        options.inJustDecodeBounds = true;
        BitmapFactory.decodeStream(is, null, options);
        options.inSampleSize = calculateInSampleSize(destWidth, destHeight, options);
        options.inJustDecodeBounds = false;
        return BitmapFactory.decodeStream(is, null, options);
    }

    /**
     * 字节数组转bitmap
     *
     * @param data
     * @param destWidth
     * @param destHeight
     * @return
     */
    public static Bitmap bytesToBitmap(byte[] data, int destWidth, int destHeight) {
        if (destWidth < 0) {
            destWidth = DEFAULT_MAX_WIDTH;
        }
        if (destHeight < 0) {
            destHeight = DEFAULT_MAX_HEIGHT;
        }
        BitmapFactory.Options options = new BitmapFactory.Options();
        options.inJustDecodeBounds = true;
        BitmapFactory.decodeByteArray(data, 0, data.length, options);
        options.inSampleSize = calculateInSampleSize(destWidth, destHeight, options);
        options.inJustDecodeBounds = false;
        return BitmapFactory.decodeByteArray(data, 0, data.length, options);
    }

    /**
     * 字符串转bitmap
     *
     * @param stringData base64字符串数据
     * @return
     */
    public static Bitmap stringToBitmap(String stringData, int destWidth, int destHeight) {
        byte[] bytes = Base64.decode(stringData, Base64.DEFAULT);
        return bytesToBitmap(bytes, destWidth, destHeight);
    }

    /**
     * bitmap转byte[]
     *
     * @param bitmap
     * @return
     */
    public static byte[] bitmapToByte(Bitmap bitmap) {
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        bitmap.compress(Bitmap.CompressFormat.JPEG, 100, baos);
        return baos.toByteArray();
    }

    /**
     * bitmap转字符串
     *
     * @param bitmap
     * @return
     */
    public static String bitmapToString(Bitmap bitmap) {
        byte[] bytes = bitmapToByte(bitmap);
        return Base64.encodeToString(bytes, Base64.DEFAULT);
    }

    /**
     * bitmap转文件
     *
     * @param bitmap
     * @param file
     */
    public static void bitmapToFile(Bitmap bitmap, File file) {
        if (file.exists()) {
            file.delete();
        }
        FileOutputStream fos = null;
        try {
            file.createNewFile();
            fos = new FileOutputStream(file);
            bitmap.compress(Bitmap.CompressFormat.JPEG, 100, fos);
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                if (fos != null) {
                    fos.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    /**
     * bitmap顺时针旋转
     *
     * @param bitmap
     * @param degree 0-90-180-270
     * @return
     */
    public static Bitmap bitmapRotate(Bitmap bitmap, int degree) {
        int w = bitmap.getWidth();
        int h = bitmap.getHeight();
        Matrix matrix = new Matrix();
        matrix.postRotate(degree);
        return Bitmap.createBitmap(bitmap, 0, 0, w, h, matrix, true);
    }

    /**
     * bitmap镜像
     *
     * @param bmp
     * @param isHorizontal 是否水平方向
     * @return
     */
    public static Bitmap bitmapMirror(Bitmap bmp, boolean isHorizontal) {
        int w = bmp.getWidth();
        int h = bmp.getHeight();
        Matrix matrix = new Matrix();
        if (isHorizontal) {
            matrix.postScale(-1f, 1f); // 水平镜像翻转
        } else {
            matrix.postScale(1f, -1f);
        }
        return Bitmap.createBitmap(bmp, 0, 0, w, h, matrix, true);
    }

    /**
     * 添加水印bitmap到原bitmap左上角
     *
     * @param context
     * @param src
     * @param water
     * @param dp_paddingLeft
     * @param dp_paddingTop
     * @return
     */
    public static Bitmap addWaterMarkToBitmapLeftTop(Context context, Bitmap src, Bitmap water, int dp_paddingLeft, int dp_paddingTop) {
        return addWaterMarkToBitmap(src, water, ScreenUtil.dp2px(context, dp_paddingLeft), ScreenUtil.dp2px(context, dp_paddingTop));
    }

    /**
     * 添加水印bitmap到原bitmap右下角
     *
     * @param context
     * @param src
     * @param water
     * @param dp_paddingRight
     * @param dp_paddingBottom
     * @return
     */
    public static Bitmap addWaterMarkToBitmapRightBottom(Context context, Bitmap src, Bitmap water, int dp_paddingRight, int dp_paddingBottom) {
        return addWaterMarkToBitmap(src, water, src.getWidth() - water.getWidth() - ScreenUtil.dp2px(context, dp_paddingRight)
                , src.getHeight() - water.getHeight() - ScreenUtil.dp2px(context, dp_paddingBottom));
    }

    /**
     * 添加水印bitmap到原bitmap右上角
     *
     * @param context
     * @param src
     * @param water
     * @param dp_paddingRight
     * @param dp_paddingTop
     * @return
     */
    public static Bitmap addWaterMarkToBitmapRightTop(Context context, Bitmap src, Bitmap water, int dp_paddingRight, int dp_paddingTop) {
        return addWaterMarkToBitmap(src, water, src.getWidth() - water.getWidth() - ScreenUtil.dp2px(context, dp_paddingRight)
                , ScreenUtil.dp2px(context, dp_paddingTop));
    }

    /**
     * 添加水印bitmap到原bitmap左下角
     *
     * @param context
     * @param src
     * @param water
     * @param dp_paddingLeft
     * @param dp_paddingBottom
     * @return
     */
    public static Bitmap addWaterMarkToBitmapLeftBottom(Context context, Bitmap src, Bitmap water, int dp_paddingLeft, int dp_paddingBottom) {
        return addWaterMarkToBitmap(src, water, ScreenUtil.dp2px(context, dp_paddingLeft)
                , src.getHeight() - water.getHeight() - ScreenUtil.dp2px(context, dp_paddingBottom));
    }

    /**
     * 添加水印bitmap到原bitmap中间
     *
     * @param src
     * @param water
     * @return
     */
    public static Bitmap addWaterMarkToBitmapCenter(Bitmap src, Bitmap water) {
        return addWaterMarkToBitmap(src, water, (src.getWidth() - water.getWidth()) / 2
                , (src.getHeight() - water.getHeight()) / 2);
    }

    /**
     * 添加文字到bitmap左上角
     *
     * @param context
     * @param src
     * @param text
     * @param dp_paddingLeft
     * @param dp_paddingTop
     * @param sp
     * @param color
     * @return
     */
    public static Bitmap addTextToBitmapLeftTop(Context context, Bitmap src, String text, int dp_paddingLeft, int dp_paddingTop, float sp, int color) {
        Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG);
        paint.setColor(color);
        paint.setTextSize(ScreenUtil.sp2px(context, sp));
        Rect rect = new Rect();
        paint.getTextBounds(text, 0, text.length(), rect);
        return addTextToBitmap(src, text, paint, ScreenUtil.dp2px(context, dp_paddingLeft), ScreenUtil.dp2px(context, dp_paddingTop) + rect.height());
    }

    /**
     * 添加文字到bitmap右下角
     *
     * @param context
     * @param src
     * @param text
     * @param dp_paddingRight
     * @param dp_paddingBottom
     * @param sp
     * @param color
     * @return
     */
    public static Bitmap addTextToBitmapRightBottom(Context context, Bitmap src, String text, int dp_paddingRight, int dp_paddingBottom, float sp, int color) {
        Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG);
        paint.setColor(color);
        paint.setTextSize(ScreenUtil.sp2px(context, sp));
        Rect rect = new Rect();
        paint.getTextBounds(text, 0, text.length(), rect);
        return addTextToBitmap(src, text, paint, src.getWidth() - rect.width() - ScreenUtil.dp2px(context, dp_paddingRight), src.getHeight() - ScreenUtil.dp2px(context, dp_paddingBottom));
    }

    /**
     * 添加文字到bitmap右上角
     *
     * @param context
     * @param src
     * @param text
     * @param dp_paddingRight
     * @param dp_paddingTop
     * @param sp
     * @param color
     * @return
     */
    public static Bitmap addTextToBitmapRightTop(Context context, Bitmap src, String text, int dp_paddingRight, int dp_paddingTop, float sp, int color) {
        Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG);
        paint.setColor(color);
        paint.setTextSize(ScreenUtil.sp2px(context, sp));
        Rect rect = new Rect();
        paint.getTextBounds(text, 0, text.length(), rect);
        return addTextToBitmap(src, text, paint, src.getWidth() - rect.width() - ScreenUtil.dp2px(context, dp_paddingRight), ScreenUtil.dp2px(context, dp_paddingTop) + rect.height());
    }

    /**
     * 添加文字到bitmap左下角
     *
     * @param context
     * @param src
     * @param text
     * @param dp_paddingLeft
     * @param dp_paddingBottom
     * @param sp
     * @param color
     * @return
     */
    public static Bitmap addTextToBitmapLeftBottom(Context context, Bitmap src, String text, int dp_paddingLeft, int dp_paddingBottom, float sp, int color) {
        Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG);
        paint.setColor(color);
        paint.setTextSize(ScreenUtil.sp2px(context, sp));
        Rect rect = new Rect();
        paint.getTextBounds(text, 0, text.length(), rect);
        return addTextToBitmap(src, text, paint, ScreenUtil.dp2px(context, dp_paddingLeft), src.getHeight() - ScreenUtil.dp2px(context, dp_paddingBottom));
    }

    /**
     * 添加文字到bitmap中间
     *
     * @param src
     * @param text
     * @param sp
     * @param color
     * @return
     */
    public static Bitmap addTextToBitmapCenter(Context context, Bitmap src, String text, float sp, int color) {
        Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG);
        paint.setColor(color);
        paint.setTextSize(ScreenUtil.sp2px(context, sp));
        Rect rect = new Rect();
        paint.getTextBounds(text, 0, text.length(), rect);
        return addTextToBitmap(src, text, paint, (src.getWidth() - rect.width()) / 2, (src.getHeight() + rect.height()) / 2);
    }

    /**
     * 创建二维码bitmap
     *
     * @param text      二维码对应文本
     * @param imgWidth  位图宽
     * @param imgHeight 位图高
     * @param logo      logo位图
     * @return
     */
    public static Bitmap generateQRCodeBitmap(String text, int imgWidth, int imgHeight, Bitmap logo) {
        try {
            if (text == null || "".equals(text)) {
                return null;
            }
            Map<EncodeHintType, Object> hints = new HashMap<>();
            hints.put(EncodeHintType.CHARACTER_SET, "utf-8");
            hints.put(EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.H);
            BitMatrix bitMatrix = new QRCodeWriter().encode(text, BarcodeFormat.QR_CODE, imgWidth, imgHeight, hints);
            int[] pixels = new int[imgWidth * imgHeight];
            for (int y = 0; y < imgHeight; y++) {
                for (int x = 0; x < imgHeight; x++) {
                    if (bitMatrix.get(x, y)) {
                        pixels[y * imgWidth + x] = 0xff000000;
                    } else {
                        pixels[y * imgWidth + x] = 0xffffffff;
                    }
                }
            }
            Bitmap bitmap = Bitmap.createBitmap(imgWidth, imgHeight, Bitmap.Config.ARGB_8888);
            bitmap.setPixels(pixels, 0, imgWidth, 0, 0, imgWidth, imgHeight);
            if (logo != null) {
                bitmap = addLogo(bitmap, logo);
            }
            return bitmap;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    private static Bitmap addLogo(Bitmap src, Bitmap logo) {
        if (src == null) {
            return null;
        }
        int srcwidth = src.getWidth();
        int srcheight = src.getHeight();
        int logowidth = logo.getWidth();
        int logoheight = logo.getHeight();
        float scale = srcwidth * 1.0f / 5 / logowidth;
        Bitmap bitmap = Bitmap.createBitmap(srcwidth, srcheight, Bitmap.Config.ARGB_8888);
        try {
            Canvas canvas = new Canvas(bitmap);
            canvas.drawBitmap(src, 0, 0, null);
            canvas.scale(scale, scale, srcwidth / 2, srcheight / 2);
            canvas.drawBitmap(logo, (srcwidth - logowidth) / 2, (srcheight - logoheight) / 2, null);
            canvas.save();
            canvas.restore();
        } catch (Exception e) {
            bitmap = null;
            e.printStackTrace();
        }
        return bitmap;
    }

    private static Bitmap addWaterMarkToBitmap(Bitmap src, Bitmap water, int paddingLeft, int paddingTop) {
        if (src == null) {
            return null;
        }
        int width = src.getWidth();
        int height = src.getHeight();
        Bitmap bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
        Canvas canvas = new Canvas(bitmap);
        canvas.drawBitmap(src, 0, 0, null);
        canvas.drawBitmap(water, paddingLeft, paddingTop, null);
        canvas.save();
        canvas.restore();
        return bitmap;
    }

    private static Bitmap addTextToBitmap(Bitmap src, String text, Paint paint, int paddingLeft, int paddingTop) {
        Bitmap.Config config = src.getConfig();
        paint.setDither(true);
        paint.setFilterBitmap(true);
        if (config == null) {
            config = Bitmap.Config.ARGB_8888;
        }
        src = src.copy(config, true);
        Canvas canvas = new Canvas(src);
        canvas.drawText(text, paddingLeft, paddingTop, paint);
        return src;
    }

    private static int calculateInSampleSize(int destWidth, int destHeight, BitmapFactory.Options options) {
        int srcWidth = options.outWidth;
        int srcHeight = options.outHeight;
        int hScale = 1;
        int wScale = 1;
        if (srcWidth > destWidth || srcHeight > destHeight) {
            wScale = Math.round((float) srcWidth / (float) destWidth);
            hScale = Math.round((float) srcHeight / (float) destHeight);
        }
        return Math.max(wScale, hScale);
    }
}
